// go语言名言: 不要用共享内存来通信, 要用通信来共享内存
// 本节主题: 共享状态的并发
// Mutex<T>, 其实也是一个智能指针

use std::sync::{Mutex, Arc};
use std::thread;
fn main() {
   let a = Mutex::new(5);
   {
        // lock方法返回了MutexGuard, 它实现了deref, 所以可以获取它所指向的值
        let mut m = a.lock().unwrap();
        *m = 6; // 解引用
        // 由于MutexGuard也实现了drop, 所以到了花括号这里, 会自动执行drop, 实现解锁, 实现释放
   }
   println!("The a is {:?}", a);

    //  多线程下, 共享状态的并发, 利用Mutex来保护数据, 利用Arc来保证所有权(todo)
    let counter = Arc::new(Mutex::new(0));
    let mut handlers = vec![];// 用来存储线程
    for _ in 1..10 {
        // 如果counter直接就是Mutex, 则此处会报错, 因为循环会导致counter所有权反复进入不同线程
        // 所以需要使用Arc, Arc和Rc的api相同, 但是, 它能用于多线程环境
        let counter = Arc::clone(&counter);
        let handler = thread::spawn(move || {
            // 获取counter的互斥锁
            let mut m = counter.lock().unwrap();
            *m += 1;
        });
        handlers.push(handler);
    }

    for handle in handlers {
        handle.join().unwrap();
    };
    println!("counter is: {}", counter.lock().unwrap()); // 9
    // 本案例讨论了如何在多进程的条件下修改一个被Mutex保护的数据; 如何使用智能指针Arc来实现所有权的妥善管理
    // 目前为止, 学习了的智能指针: Box、Rc、RefCell、Mutex、Arc
}

// 16.4中的概念
// 1. rust中有两个并发概念, Send和Sync, 这俩trait都来自std::marker
// 2. 这俩是标签trait, 没有任何的方法
// 3. Send允许在不同线程间转移所有权, 实现了Send的类型就可以在线程间转移所有权, rust几乎所有类型都实现了Send
// 但是Rc<T>没有实现, 故而不能在线程间转交所有权;
// 4. 完全由Send组成的类型也被标记为Send
// 5. 实现Sync的类型可以被多个线程引用, 如果T是Sync, 那么&T就是Send
// 6. 基础类型都实现了Sync; Rc<T>, RefCell<T>, Cell<T>都不是Sync的; Mutex实现了Sync; 
// 7. 手动实现Sync和Send不安全
